package com.sudo.service.admin.runnable;

import com.sudo.common.component.SpringContextUtil;
import com.sudo.common.service.BaseService;
import com.sudo.common.utils.JsonUtil;
import com.sudo.common.utils.ThreadLocalUtil;
import com.sudo.dao.admin.entity.SysMethodJob;
import com.sudo.service.tldata.ThreadLocalObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;

/**
 * 每一个定时任务都对应一个子线程
 */
@Slf4j
public class BeanMethodRunnable extends BaseService implements Runnable{
    private Integer id;
    private String beanName;
    private String methodName;
    private String params;
    private String logStatus;
    private String mailStatus;
    private String mailAddress;

    private Object targetBean;
    private Method method;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBeanName() {
        return beanName;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public String getParams() {
        return params;
    }

    public void setParams(String params) {
        this.params = params;
    }

    public String getLogStatus() {
        return logStatus;
    }

    public void setLogStatus(String logStatus) {
        this.logStatus = logStatus;
    }

    public String getMailStatus() {
        return mailStatus;
    }

    public void setMailStatus(String mailStatus) {
        this.mailStatus = mailStatus;
    }

    public String getMailAddress() {
        return mailAddress;
    }

    public void setMailAddress(String mailAddress) {
        this.mailAddress = mailAddress;
    }

    public BeanMethodRunnable(Integer id, String beanName, String methodName) {
        this.id = id;
        this.beanName = beanName;
        this.methodName = methodName;
    }

    public BeanMethodRunnable(SysMethodJob sysMethodJob) {
        this.id = sysMethodJob.getId();
        this.beanName = sysMethodJob.getBeanName();
        this.methodName = sysMethodJob.getMethodName();
        this.params = sysMethodJob.getMethodParams();
        this.logStatus = sysMethodJob.getLogStatus();
        this.mailStatus = sysMethodJob.getMailStatus();
        this.mailAddress = sysMethodJob.getMailAddress();
        init();
    }

    public void init() {
        try {
            targetBean = SpringContextUtil.getBean(beanName);
            if (StringUtils.hasText(params)) {
                // 假设定时任务只有一个参数，并且参数类型是 Map 类型
                method = targetBean.getClass().getDeclaredMethod(methodName, Map.class);
            }else {
                method = targetBean.getClass().getDeclaredMethod(methodName);
            }
            // 使方法可访问
            ReflectionUtils.makeAccessible(method);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        log.info("定时任务开始执行 - id：{}，bean：{}，方法：{}，参数：{}",id,beanName,method,params);
        long startTime = System.currentTimeMillis();
        try {
            Map<String, Object> jobConfigMap = ThreadLocalObject.initJobConfigMap(this);
            ThreadLocalUtil.setTlMap(jobConfigMap);
            if ((StringUtils.hasText(params))) {
                Map<String, Object> paramMap = JsonUtil.jsonToPojo(params, Map.class);
                method.invoke(targetBean, paramMap);
            }else {
                method.invoke(targetBean);
            }
        } catch (Exception e) {
            throw new RuntimeException("任务["+id+"]自动执行失败");
        }
        long endTime = System.currentTimeMillis();
        log.info("定时任务执行结束 - id：{}，bean：{}，方法：{}，参数：{}，耗时：{}毫秒",id,beanName,method,params,(endTime-startTime));
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        BeanMethodRunnable that = (BeanMethodRunnable) o;
        return Objects.equals(id, that.id)
                && Objects.equals(beanName, that.beanName)
                && Objects.equals(methodName, that.methodName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id,beanName, methodName);
    }
}
